A task is a set of computer-executable instructions that process data. A task may read, manipulate, and/or write data. Traditionally, when a task is started, a thread is created to perform the task, and when the task has ended, the thread is terminated. A thread is the lowest-level execution of a set of instructions (i.e., the execution of a task), where a number of threads may be concurrently performed to execute a process of a computer program. A process may encompass one or more concurrently executing and/or non-concurrently executing threads. The terms “thread” and “task” are used interchangeably herein.
Tasks may be bound to processors or processor groups. Bound tasks are to be executed by the processors or processor groups to which they have been bound and are not to be executed by any other processors or processor groups. For example, a technique available in the kernel of the LINUX operating system known as Cpusets permits a thread to be bound to a processor or a set of processors. A task bound to a given Cpuset is executed by the processors assigned to the Cpuset and cannot be executed by any other processor that may be available.
While processor groups like Cpusets can provide for processor availability guarantees and some degree of processor load balancing, nevertheless they can result in poor processor utilization. For example, a first set of tasks may be bound to a first processor group, and a second set of tasks may be bound to a second processor group. The two processor groups may be non-overlapping, such that a processor belongs to one and only one of the two processor groups. The first set of tasks currently may be active, such that the processors of the first processor group are running at maximum utilization to execute the first set of tasks. By comparison, the second set of tasks currently may be inactive, such that the processors of the second processor group are currently idle. However, since the first set of tasks is bound to the first processor group, the idle processors of the second processor group cannot be used to execute the first set of tasks.
A partial solution is provided within the known art in that tasks can be migrated from one processor group to another processor group. In accordance with such partial solution, a task initially may be bound to a first processor group. Then, the task may be migrated from the first processor group to a second processor group. As a result of such migration, the task is executed by the processors of the second processor group and not by any processor that is not within this second processor group. However, once the task has been migrated from the first processor group to the second processor group, it no longer has any residual binding or other relationship with respect to the first processor group.
Furthermore, in accordance with the known art, the user has no preferential control over the processor groups to which a task is migrated. For example, consider a large university server having the following processor groups: math/professors, math/students, physics/professors, and physics/students. These groups are allocated to professors of the math department, students of the math department, professors of the physics department, and students of the physics department, respectively. It is desired that when migrating a task from the math/professors processor group, the task is first migrated to the math/students processor group, followed by to the physics/students processor group, and finally to the physics/professors processor group. However, the known art does not provide any control over the order in which such task migration is attempted.
Furthermore, the known art does not provide a mechanism to specify thresholds for load balancing. For example, it may be desirable to specify that the physics/professor group can accept foreign tasks (i.e., tasks belong to other processor groups) only when it has more than 50% idle time. However, the known art does not provide for such specifications.